home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 3
/
Cream of the Crop 3.iso
/
comm
/
wnos5src.zip
/
DOMSUBR.C
< prev
next >
Wrap
Text File
|
1993-10-14
|
38KB
|
1,591 lines
#include <ctype.h>
#include "global.h"
#include "config.h"
#include "mbuf.h"
#include "domain.h"
#include "netuser.h"
#include "socket.h"
#include "files.h"
static struct rr *Rrlist[NRLIST];
#ifdef ENH
struct dlist *Lorigin = NULLDLIST;
struct rr *Rrlistl[NRLIST];
char *Dorigin = NULLCHAR;
#else
static struct dlist *Lorigin = NULLDLIST;
static struct rr *Rrlistl[NRLIST];
static char *Dorigin = NULLCHAR;
#endif
/*
static int near
strxlen(char *s)
{
int i = 0;
while(*s++ != '\0')
i++;
return i;
}
*/
int
sendquery(int32 address,char *buf,int len,struct mbuf **bp,int32 timeout)
{
int s, resp = -1;
if((s = socket(AF_INET,SOCK_DGRAM,0)) != -1) {
struct sockaddr_in server;
*bp = qdata(buf,len);
xfree(buf);
server.sin_family = AF_INET;
server.sin_port = IPPORT_DOMAIN;
server.sin_addr.s_addr = address;
send_mbuf(s,*bp,0,(char *)&server,SOCKSIZE);
if(timeout) { /* Wait for something to happen */
alarm(timeout);
resp = recv_mbuf(s,bp,0,NULLCHAR,0);
alarm(0L);
}
close_s(s);
}
return resp;
}
static char * near
dn_compress(char *cp,char *name)
{
int dlen = strlen(name);
for(;;){
/* Look for next dot */
char *cp1 = strchr(name,'.');
int len = (cp1 != NULLCHAR) ? (int)(cp1 - name) : dlen;
*cp++ = len; /* Write length of component */
if(len == 0) {
return cp;
}
/* Copy component up to (but not including) dot */
strncpy(cp,name,len);
cp += len;
if(cp1 == NULLCHAR) {
*cp++ = 0; /* Last one; write null and finish */
return cp;
}
name += len+1;
dlen -= len+1;
}
}
/* Convert a compressed domain name to the human-readable form */
static int near
dn_expand(
char *msg, /* Complete domain message */
char *eom,
char *compressed, /* Pointer to compressed name */
char *full, /* Pointer to result buffer */
int fullen) /* Length of same */
{
int clen = 0; /* Total length of compressed name */
int indirect = 0; /* Set if indirection encountered */
int nseg = 0; /* Total number of segments in name */
char *cp = compressed;
for(;;){
unsigned int slen = uchar(*cp++); /* Length of this segment */
if(!indirect) {
clen++;
}
if((slen & 0xc0) == 0xc0) {
if(!indirect) {
clen++;
}
indirect = 1;
/* Follow indirection */
cp = &msg[((slen & 0x3f)<<8) + uchar(*cp)];
slen = uchar(*cp++);
}
if(slen == 0) { /* zero length == all done */
break;
}
if((fullen -= slen + 1) < 0) {
return -1;
}
if(!indirect) {
clen += slen;
}
while(slen-- != 0) {
*full++ = *cp++;
}
*full++ = '.';
nseg++;
}
if(nseg == 0) {
/* Root name; represent as single dot */
*full++ = '.';
fullen--;
}
*full++ = '\0';
fullen--;
return clen; /* Length of compressed message */
}
static char * near
getq(struct quest *qp,char *msg,char *cp)
{
int len;
char name[512];
if((len = dn_expand(msg,NULLCHAR,cp,name,sizeof(name))) == -1) {
return NULLCHAR;
}
cp += len;
qp->qname = strxdup(name);
qp->qtype = get16(cp);
cp += 2;
qp->qclass = get16(cp);
cp += 2;
return cp;
}
/* Read a resource record from a domain message into a host structure */
static char * near
ntohrr(
struct rr *rrp, /* Pointer to allocated resource record structure */
char *msg, /* Pointer to beginning of domain message */
char *cp) /* Pointer to start of encoded RR record */
{
int len;
char name[512];
if((len = dn_expand(msg,NULLCHAR,cp,name,sizeof(name))) == -1) {
return NULLCHAR;
}
cp += len;
rrp->name = strxdup(name);
rrp->type = get16(cp);
cp += 2;
rrp->class = get16(cp);
cp+= 2;
rrp->ttl = get32(cp);
cp += 4;
rrp->rdlength = get16(cp);
cp += 2;
switch(rrp->type){
case TYPE_CNAME:
case TYPE_MB:
case TYPE_MG:
case TYPE_MR:
case TYPE_NS:
case TYPE_PTR:
/* These types all consist of a single domain name;
* convert it to ascii format
*/
if((len = dn_expand(msg,NULLCHAR,cp,name,sizeof(name))) == -1) {
return NULLCHAR;
}
rrp->rdata.name = strxdup(name);
cp += len;
break;
case TYPE_A:
/* Just read the address directly into the structure */
rrp->rdata.addr = get32(cp);
cp += 4;
break;
case TYPE_HINFO:
rrp->rdata.hinfo.cpu = mxallocw(*cp + 1);
strncpy(rrp->rdata.hinfo.cpu,cp+1,*cp);
cp += *cp + 1;
rrp->rdata.hinfo.os = mxallocw(*cp + 1);
strncpy(rrp->rdata.hinfo.os,cp+1,*cp);
cp += *cp + 1;
break;
case TYPE_MX:
rrp->rdata.mx.pref = get16(cp);
cp += 2;
/* Get domain name of exchanger */
if((len = dn_expand(msg,NULLCHAR,cp,name,sizeof(name))) == -1) {
xfree(rrp->name);
return NULLCHAR;
}
rrp->rdata.mx.exch = strxdup(name);
cp += len;
break;
case TYPE_SOA:
/* Get domain name of name server */
if((len = dn_expand(msg,NULLCHAR,cp,name,sizeof(name))) == -1) {
xfree(rrp->name);
return NULLCHAR;
}
rrp->rdata.soa = mxallocw(sizeof(struct soa));
rrp->rdata.soa->mname = strxdup(name);
cp += len;
/* Get domain name of responsible person */
if((len = dn_expand(msg,NULLCHAR,cp,name,sizeof(name))) == -1) {
xfree(rrp->rdata.soa->mname);
xfree(rrp->rdata.soa);
xfree(rrp->name);
return NULLCHAR;
}
rrp->rdata.soa->rname = strxdup(name);
cp += len;
rrp->rdata.soa->serial = get32(cp);
cp += 4;
rrp->rdata.soa->refresh = get32(cp);
cp += 4;
rrp->rdata.soa->retry = get32(cp);
cp += 4;
rrp->rdata.soa->expire = get32(cp);
cp += 4;
rrp->rdata.soa->minimum = get32(cp);
cp += 4;
break;
case TYPE_TXT:
/* Just stash */
rrp->rdata.data = mxallocw(rrp->rdlength);
memcpy(rrp->rdata.data,cp,rrp->rdlength);
cp += rrp->rdlength;
break;
case TYPE_MD: /* Not supported */
case TYPE_MF: /* Not supported */
case TYPE_NULL: /* Not supported */
case TYPE_WKS: /* Not supported */
case TYPE_MINFO: /* Not supported */
if((len = dn_expand(msg,NULLCHAR,cp,name,sizeof(name))) == -1) {
xfree(rrp->name);
return NULLCHAR;
}
rrp->rdata.name = strxdup(name);
cp += len;
break;
default:
/* Ignore */
cp += rrp->rdlength;
break;
}
return cp;
}
static char * near
htonrr(struct rr *rr,char *buffer)
{
struct rr *rrp;
char *cp = buffer;
for(rrp = rr; rrp != NULLRR; rrp = rrp->next) {
int i = strlen(rrp->name), len;
if(rrp->name[i-1] != '.' && rrp->origin != NULLCHAR) {
char *p = mxallocw(i + strlen(rrp->origin) + 2);
sprintf(p,"%s.%s",rrp->name,rrp->origin);
cp = dn_compress(cp,p);
xfree(p);
} else {
cp = dn_compress(cp,rrp->name);
}
cp = put16(cp,rrp->type);
cp = put16(cp,rrp->class);
cp = put32(cp,3600L); /* time to live */
cp = put16(cp,rrp->rdlength);
switch(rrp->type) {
case TYPE_A:
cp = put32(cp,rrp->rdata.addr);
break;
case TYPE_SOA:
cp = dn_compress(cp,rrp->rdata.soa->mname);
cp = dn_compress(cp,rrp->rdata.soa->rname);
cp = put32(cp,rrp->rdata.soa->serial);
cp = put32(cp,rrp->rdata.soa->refresh);
cp = put32(cp,rrp->rdata.soa->retry);
cp = put32(cp,rrp->rdata.soa->expire);
cp = put32(cp,rrp->rdata.soa->minimum);
break;
case TYPE_HINFO:
*cp++ = len = strlen(rrp->rdata.hinfo.cpu);
strncpy(cp,rrp->rdata.hinfo.cpu,len);
cp += len;
*cp++ = len = strlen(rrp->rdata.hinfo.os);
strncpy(cp,rrp->rdata.hinfo.os,len);
cp += len;
break;
case TYPE_MX:
cp = put16(cp,rrp->rdata.mx.pref);
cp = dn_compress(cp,rrp->rdata.mx.exch);
break;
case TYPE_CNAME:
case TYPE_MB:
case TYPE_MG:
case TYPE_MR:
case TYPE_NS:
case TYPE_PTR:
cp = dn_compress(cp,rrp->rdata.data);
break;
case TYPE_MINFO: /* Unsupported type */
cp = dn_compress(cp,rrp->rdata.minfo.rmailbx);
cp = dn_compress(cp,rrp->rdata.minfo.emailbx);
case TYPE_MD: /* Unsupported type */
case TYPE_MF: /* Unsupported type */
case TYPE_NULL: /* Unsupported type */
case TYPE_WKS: /* Unsupported type */
cp = dn_compress(cp,rrp->rdata.data);
break;
case TYPE_TXT:
default:
cp = put16(cp,rrp->rdlength);
for(i=0 ; i < rrp->rdlength ; i++) {
*cp++ = rrp->rdata.data[i];
}
break;
}
}
return cp;
}
/* analyse suffixes for names to be added to the memory list */
/* if Lorigin is empty, PA0GRI's domain stuf is not active. */
static void near
analsuf(struct rr *rrp)
{
struct dlist *llist, *lorigin;
if(rrp->origin != NULLCHAR) {
/* no job for me. */
return;
}
if((llist = Lorigin) != NULLDLIST) { /* Am i working for PA0GRI? */
int i = strlen(rrp->name);
if(rrp->name[i-1] == '.') {
char *n1 = &rrp->name[i-1];
char *n2 = strchr(rrp->name,'.');
if(n1 == n2) {
return; /* only 1 dot */
}
n2++; /* point byond dot */
while(llist != NULLDLIST) {
lorigin = llist;
if(strcmp(llist->name,n2) == 0) {
break;
}
llist = llist->next;
}
if(llist == NULLDLIST) {
llist = mxallocw(sizeof(struct dlist));
llist->name = strxdup(n2);
lorigin->next = llist;
}
rrp->origin = llist->name;
n2--;
*n2 = '\0'; /* dot to EOS */
n1 = strxdup(rrp->name);
xfree(rrp->name);
rrp->name = n1;
}
}
}
/* test a rr against a given name and type. The name can be:
1 a fully qualified name (EG: pa0gri.ampr.org.)
or (if not fully qualified)
2 a name without a dot and no origin and suffix
3 a name without a dot and an origin and no suffix
4 a name without a dot and an origin and a suffix
*
* return 0 if not comparable, case value if it is good
*/
static int near
dfind_cmp(struct rr *rrp,char *name,int nlen,int dlen)
{
int olen = 0, rlen = strlen(rrp->name);
if(rrp->origin != NULLCHAR) {
olen = strlen(rrp->origin);
if(rrp->origin[olen - 1] == '.')
--olen;
}
/* 1st test: is the name equal to the fully qualified rrp name? (minus traling .) */
if(rrp->name[rlen - 1] == '.') {
--rlen;
if(rlen == nlen && strnicmp(name,rrp->name,rlen) == 0)
return 1;
}
/* second test: is the name equal to the rrp name */
if(Dsuffix == NULLCHAR && rrp->origin == NULLCHAR) {
if(nlen == rlen && strnicmp(name,rrp->name,rlen) == 0)
return 2;
if(nlen + 9 == rlen /* special case for .ampr.org. */
&& strnicmp(name,rrp->name,nlen) == 0
&& strnicmp(&rrp->name[nlen+1],"ampr.org",8) == 0
&& rrp->name[nlen] == '.')
return 3;
} else if(Dsuffix == NULLCHAR && rrp->origin != NULLCHAR) {
if(nlen == rlen && strnicmp(name,rrp->name,rlen) == 0)
/* third test: name equal to rrp name (excluding origin) */
return 4;
else if((rlen + olen + 1) == nlen
&& strnicmp(name,rrp->name,rlen) == 0
&& name[rlen] == '.'
&& strnicmp(&name[rlen + 1],rrp->origin,olen) == 0)
/* fourth test: name equal rrp name + origin */
return 5;
} else if(Dsuffix != NULLCHAR && rrp->origin != NULLCHAR) {
if(rlen == nlen && dlen == olen
&& strnicmp(name,rrp->name,rlen) == 0
&& strnicmp(Dsuffix,rrp->origin,dlen) == 0)
/* fifth test: name equal to rrp name and origin equal to domain suffix */
return 6;
else if((rlen + olen + 1) == nlen
&& strnicmp(name,rrp->name,rlen) == 0
&& name[rlen] == '.'
&& strnicmp(&name[rlen + 1],rrp->origin,olen) == 0)
/* sixth test: name equal to rrp name + origin) */
return 7;
} else if(Dsuffix != NULLCHAR && rrp->origin == NULLCHAR) {
if(rlen == nlen && strnicmp(name,rrp->name,rlen) == 0)
/* seventh test: name equal to rrp name and no origin (ignore domain suffix) */
return 8;
else
if((nlen + dlen + 1) == rlen
&& strnicmp(name,rrp->name,nlen) == 0
&& rrp->name[nlen] == '.'
&& strnicmp(&rrp->name[nlen + 1],Dsuffix,dlen) == 0)
/* eight test: name plus suffix equal to rrp name ) */
return 9;
}
return 0;
}
/* Search local domain file for resource record of specified name and type.
* If records were found, the domain file pointer is left just after the last
* one. If not, the file is rewound.
*/
static struct rr * near
dfindf(FILE *dbase,char *name,int type,struct rr_memory *memory)
{
struct rr *rrp;
int nlen = strlen(name);
int dlen = (Dsuffix != NULLCHAR) ? (strlen(Dsuffix) - 1) : 0;
if(DBloaded) {
return NULLRR;
}
if(name[nlen - 1] == '.') { /* forget trailing . for tests. */
--nlen;
}
/* Search file */
while((rrp = get_rr(dbase,memory)) != NULLRR) {
if(rrp->class == CLASS_IN) {
if(type == rrp->type || type == TYPE_ANY) {
if(dfind_cmp(rrp,name,nlen,dlen) != 0) {
break;
}
}
}
free_rr(rrp);
pwait(NULL); /* Give up CPU for a while, this takes time */
}
if(rrp == NULLRR) {
rewind(dbase);
}
return rrp;
}
#ifdef forgetme
/* If the first character is a '*' it is replaced by the
first part of the sought domain. */
/* forget about this till other areas know what to do with multiple rr's.
if(*rrp->name == '*'){
if(rrp->name[rlen-1] == '.')
p = mxallocw(rlen);
else
p = mxallocw(rlen + olen);
strcpy(p,rrp->name+2);
if(rrp->name[rlen-1] != '.' && rrp->origin != NULLCHAR)
strcat(p,rrp->origin);
rrp->origin = p;
olen = strlen(rrp->origin);
if(rrp->origin[olen-1] == '.')
--olen;
xfree(rrp->name);
rrp->name = mxallocw(nlen + 1);
if(nlen > olen
&& strnicmp(name+nlen-olen,rrp->origin, olen) == 0)
strncpy(rrp->name,name,nlen-olen-1);
else {
free_rr(rrp);
continue;
}
rlen = strlen(rrp->name);
}
end of skip code */
#endif
struct rr *
dfind(FILE *dbase,char *name,int type,struct rr_memory *memory)
{
struct rr *rrp, *rrl;
int nlen, i, rtype;
int dlen = (Dsuffix != NULLCHAR) ? (strlen(Dsuffix) - 1) : 0;
struct rr *rrsave = NULLRR;
if(type >= NDTYPES) {
if(type == TYPE_ANY) {
for(i = 0 ; (rtype = Dstypes[i]) != 0; ) {
rrp = dfind(dbase,name,rtype,memory);
if(rrp != NULLRR) {
if(rrsave == NULLRR){
rrsave = rrp;
rrl = rrp;
} else {
rrl->next = rrp;
rrl = rrl->next;
}
} else {
i++;
memory->rrp = NULLRR;
}
}
if(rrsave != NULLRR) {
return rrsave;
}
} else {
/* to big a type for memory */
goto filetest;
}
}
if((rrp = Rrlist[type]) != NULLRR) {
if(memory->rrp != NULLRR) {
rrp = memory->rrp; /* go off where we left before ! */
rrp = rrp->next; /* but take the next */
}
nlen = strlen(name);
if(name[nlen - 1] == '.') { /* forget trailing . for tests. */
--nlen;
}
/* Search core data beast */
while(rrp != NULLRR) {
if(rrp->class == CLASS_IN) {
if(dfind_cmp(rrp,name,nlen,dlen) != 0) {
break;
}
}
rrp = rrp->next;
}
if(rrp != NULLRR){
rrl = copy_rr(rrp);
memory->rrp = rrp;
return rrl;
}
memory->rrp = NULLRR; /* end of list encountered */
} /* not found in memory, resort to file */
filetest:
if(dbase != NULLFILE) {
rrp = dfindf(dbase,name,type,memory);
}
return rrp;
}
/* Add a record to the database only if it doesn't already exist */
/* Return 1 if record is not added to memory list. This means the rr
can be freed. If 0 is returned the rr is added to the memory list */
#ifndef ENH
static
#endif
int
add_rr(FILE *fp,struct rr *rrp1)
{
int type, nlen;
char *name;
struct rr *rrp, *rr;
struct rr_memory *memory = mxallocw(sizeof(struct rr_memory));
memory->rrp = NULLRR;
analsuf(rrp1);
type = rrp1->type;
name = rrp1->name;
nlen = strlen(name);
if(fp == NULLFILE) {
name = strxdup(rrp1->name);
while((rrp = dfind(fp,name,type,memory)) != NULLRR) {
if(cmp_rr(rrp,rrp1) == 0) {
free_rr(rrp);
xfree(memory->dorigin);
xfree(memory);
xfree(name);
return 1;
}
free_rr(rrp);
}
/* Not found in list, go add it */
xfree(memory->dorigin);
xfree(memory);
xfree(name);
/* see if we have this kind of records. */
if((rr = Rrlist[type]) != NULLRR) {
rr = Rrlistl[type];
rr->next = rrp1;
} else { /* No, initialize first */
Rrlist[rrp1->type] = rrp1;
}
/* now set last */
Rrlistl[type] = rrp1;
return 0;
} else {
if(name[nlen - 1] != '.') {
if(rrp1->origin != NULLCHAR){
name = mxallocw(nlen + strlen(rrp1->origin) + 2);
sprintf(name,"%s.%s",rrp1->name,rrp1->origin);
}
} else {
name = strxdup(rrp1->name);
}
rewind(fp);
while((rrp = dfind(fp,name,type,memory)) != NULLRR) {
if(cmp_rr(rrp,rrp1) == 0) {
free_rr(rrp);
xfree(memory->dorigin);
xfree(memory);
xfree(name);
return 1;
}
free_rr(rrp);
}
xfree(memory->dorigin);
xfree(memory);
xfree(name);
fseek(fp,0,SEEK_END);
put_rr(fp,rrp1,1);
return 1;
}
}
/* Compare two resource records, returning 0 if equal, nonzero otherwise */
static int
cmp_rr(struct rr *rr1,struct rr *rr2)
{
int i;
if(rr1 == NULLRR || rr2 == NULLRR) {
return -1;
}
if((i = strlen(rr1->name)) != strlen(rr2->name)) {
return 1;
}
if((i = strnicmp(rr1->name,rr2->name,i)) != 0) {
return i;
}
if(rr1->type != rr2->type) {
return 2;
}
if(rr1->class != rr2->class) {
return 3;
}
if(rr1->rdlength == 0 && rr2->rdlength == 0) {
return 0;
}
if(rr1->rdlength == 0 || rr2->rdlength == 0) {
return 4;
}
/* Note: rdlengths are not compared because they vary depending
* on the representation (ASCII or encoded) this record was
* generated from.
*/
switch(rr1->type){
case TYPE_A:
i = rr1->rdata.addr != rr2->rdata.addr;
break;
case TYPE_SOA:
i = rr1->rdata.soa->serial != rr2->rdata.soa->serial;
break;
case TYPE_HINFO:
i = strcmp(rr1->rdata.hinfo.cpu,rr2->rdata.hinfo.cpu) ||
strcmp(rr1->rdata.hinfo.os,rr2->rdata.hinfo.os);
break;
case TYPE_MX:
i = strcmp(rr1->rdata.mx.exch,rr2->rdata.mx.exch);
break;
case TYPE_MINFO: /* Unsupported type */
i = strcmp(rr1->rdata.minfo.rmailbx,rr2->rdata.minfo.rmailbx) ||
strcmp(rr1->rdata.minfo.emailbx,rr2->rdata.minfo.emailbx);
break;
case TYPE_MB:
case TYPE_MG:
case TYPE_MR:
case TYPE_PTR:
case TYPE_TXT:
case TYPE_NS:
case TYPE_CNAME:
/*
i = strcmp(rr1->rdata.data,rr2->rdata.data);
break;
*/
case TYPE_MD: /* Unsupported type */
case TYPE_MF: /* Unsupported type */
case TYPE_NULL: /* Unsupported type */
case TYPE_WKS: /* Unsupported type */
i = strcmp(rr1->rdata.data,rr2->rdata.data);
break;
}
return i;
}
struct rr *
copy_rr(struct rr *rr)
{
struct rr *rrp = mxallocw(sizeof(struct rr));
rrp->next = NULLRR;
rrp->soarec = rr->soarec;
rrp->name = strxdup(rr->name);
rrp->type = rr->type;
rrp->class = rr->class;
rrp->ttl = rr->ttl;
rrp->origin = rr->origin;
rrp->rdlength = rr->rdlength;
switch(rr->type){
case TYPE_A:
rrp->rdata.addr = rr->rdata.addr;
break;
case TYPE_HINFO:
rrp->rdata.hinfo.cpu = strxdup(rr->rdata.hinfo.cpu);
rrp->rdata.hinfo.os = strxdup(rr->rdata.hinfo.os);
break;
case TYPE_MX:
rrp->rdata.mx.pref = rr->rdata.mx.pref;
rrp->rdata.mx.exch = strxdup(rr->rdata.mx.exch);
break;
case TYPE_SOA:
rrp->rdata.soa = mxallocw(sizeof(struct soa));
rrp->rdata.soa->mname = strxdup(rr->rdata.soa->mname);
rrp->rdata.soa->rname = strxdup(rr->rdata.soa->rname);
rrp->rdata.soa->serial = rr->rdata.soa->serial;
rrp->rdata.soa->refresh = rr->rdata.soa->refresh;
rrp->rdata.soa->retry = rr->rdata.soa->retry;
rrp->rdata.soa->expire = rr->rdata.soa->expire;
rrp->rdata.soa->minimum = rr->rdata.soa->minimum;
break;
case TYPE_MINFO: /* Unsupported type */
rrp->rdata.minfo.rmailbx = strxdup(rr->rdata.minfo.rmailbx);
rrp->rdata.minfo.emailbx = strxdup(rr->rdata.minfo.emailbx);
break;
case TYPE_CNAME:
case TYPE_MB:
case TYPE_MG:
case TYPE_MR:
case TYPE_NS:
case TYPE_PTR:
case TYPE_TXT:
/*
rrp->rdata.name = strxdup(rr->rdata.name);
break;
*/
case TYPE_MD: /* Unsupported type */
case TYPE_MF: /* Unsupported type */
case TYPE_NULL: /* Unsupported type */
case TYPE_WKS: /* Unsupported type */
rrp->rdata.name = strxdup(rr->rdata.name);
break;
}
return rrp;
}
#ifdef XXX
struct rr *
make_rr(int source,char *dname,int16 dclass,int16 dtype,int32 ttl,int16 rdl,void *data)
{
struct rr *newrr = mxallocw(sizeof(struct rr));
newrr->next = NULLRR;
newrr->soarec = NULLRR;
newrr->name = strxdup(dname);
newrr->class = dclass;
newrr->type = dtype;
newrr->ttl = ttl;
if((newrr->rdlength = rdl) == 0) {
return newrr;
}
if(dtype == TYPE_A) {
int32 *ap = (int32 *)data;
newrr->rdata.addr = *ap;
}
return copy_rr(newrr);
}
#endif
/* Free a chain of resource records */
void
free_rr(struct rr *rrp)
{
struct rr *rr = rrp;
while(rr != NULLRR) {
rrp = rr;
xfree(rrp->name);
if(rrp->rdlength != 0){
switch(rrp->type){
case TYPE_CNAME:
case TYPE_MB:
case TYPE_MG:
case TYPE_MR:
case TYPE_NS:
case TYPE_PTR:
xfree(rrp->rdata.name);
break;
case TYPE_A:
break; /* Nothing allocated in rdata section */
case TYPE_HINFO:
xfree(rrp->rdata.hinfo.cpu);
xfree(rrp->rdata.hinfo.os);
break;
case TYPE_MX:
xfree(rrp->rdata.mx.exch);
break;
case TYPE_SOA:
xfree(rrp->rdata.soa->mname);
xfree(rrp->rdata.soa->rname);
xfree(rrp->rdata.soa);
break;
case TYPE_TXT:
xfree(rrp->rdata.data);
break;
case TYPE_MD: /* Unsupported type */
case TYPE_MF: /* Unsupported type */
case TYPE_NULL: /* Unsupported type */
xfree(rrp->rdata.data);
break;
case TYPE_WKS: /* Unsupported type */
break;
case TYPE_MINFO: /* Unsupported type */
xfree(rrp->rdata.minfo.rmailbx);
xfree(rrp->rdata.minfo.emailbx);
break;
}
}
rr = rrp->next;
xfree(rrp);
}
}
#define LEN 128
#ifndef ENH
static
#endif
struct rr *
get_rr(FILE *fp,struct rr_memory *memory)
{
char line[LEN], contline[LEN];
struct rr *rrp;
struct dlist *lorigin,*ltemp;
char *name, *ttl, *class, *type, *data;
int i;
int32 value;
static char delim[] = " \t\r\n";
if(fp == NULLFILE) {
return NULLRR;
}
/* Search file */
while(fgets(line,LEN,fp) != NULL) {
if(*line == '#' || *line == ';') {
continue;
}
if(*line == '$') {
data = strtok(line,delim);
if(strnicmp(data,"$origin",7) == 0) {
data = strtok(NULLCHAR,delim);
if(Db_initialize) {
if(data != NULLCHAR) {
ltemp = Lorigin;
while(ltemp != NULLDLIST) {
lorigin = ltemp;
if(strcmp(ltemp->name,data) == 0) {
break;
}
ltemp = ltemp->next;
}
if(ltemp == NULLDLIST) {
ltemp = mxallocw(sizeof(struct dlist));
ltemp->name = strxdup(data);
lorigin->next = ltemp;
Dorigin = ltemp->name;
} else {
Dorigin = ltemp->name;
}
} else {
Dorigin = NULLCHAR; /* empty origin */
}
}
if(memory->dorigin != NULLCHAR) {
xfree(memory->dorigin);
}
memory->dorigin = (data != NULLCHAR) ? strxdup(data) : NULLCHAR;
}
continue;
}
data = &line[0]; /* check for empty line */
while(*data)
if(!isspace(*data++)) {
break;
}
/*
* now it is nor a # , ; or $ line
*/
if(*data) {
break; /* there is something on it.. */
}
}
if(feof(fp)) {
return NULLRR;
}
rrp = mxallocw(sizeof(struct rr));
if(isspace(line[0])) { /* in case of previous name usage*/
name = "";
ttl = strtok(line,delim);
} else {
name = strtok(line,delim);
if(*name == '@' && (memory->dorigin != NULLCHAR
|| Dsuffix != NULLCHAR)){
name = (memory->dorigin != NULLCHAR) ? memory->dorigin : Dsuffix;
}
ttl = strtok(NULLCHAR,delim);
}
if(ttl == NULLCHAR) { /* If a line only contains a name */
goto badline;
}
if((i = strlen(name)) == 0) {
name = memory->Dname;
} else {
sprintf(memory->Dname,"%.125s",name);
}
rrp->origin = (Dorigin != NULLCHAR) ? Dorigin : memory->dorigin;
if(name[i-1] == '.') { /* if a fully qualified name comes along */
rrp->origin = NULLCHAR; /* then it does not belong to an origin */
}
rrp->name = strxdup(name);
if(!isdigit(ttl[0])) {
/* Optional ttl field is missing; slide field over */
class = ttl;
ttl = NULLCHAR;
rrp->ttl = memory->Dttl;
} else {
memory->Dttl = atol(ttl);
rrp->ttl = memory->Dttl;
class = strtok(NULLCHAR,delim);
}
if(class == NULLCHAR) { /* If a line only contains a name and ttl */
goto badline;
}
if(strcmp(class,"IN") != 0){
/* Optional class field is missing; slide field over */
type = class;
class = NULLCHAR;
rrp->class = memory->Dclass;
} else {
memory->Dclass = CLASS_IN;
rrp->class = memory->Dclass;
type = strtok(NULLCHAR,delim);
}
if(type == NULLCHAR) { /* If a class field is missing */
badline:
tprintf("Error in domain file %s:\n-%s-\n",Dfile,line);
free_rr(rrp);
return NULLRR;
}
for(i = 0; i < NRLIST; i++) {
if(strcmp(type,type2str(i)) == 0) {
rrp->type = i;
break;
}
}
data = strtok(NULLCHAR,delim);
if(data == NULLCHAR) {
return rrp;
}
switch(rrp->type){
case TYPE_MD: /* Unsupported yet */
case TYPE_MF: /* Unsupported yet */
case TYPE_NULL: /* Unsupported yet */
/*
rrp->rdlength = strlen(data) + 1;
rrp->rdata.name = strxdup(data);
break;
*/
case TYPE_WKS: /* Unsupported yet */
/*
rrp->wks = mxallocw(sizeof(struct wks));
*/
case TYPE_CNAME:
case TYPE_MB:
case TYPE_MG:
case TYPE_MR:
case TYPE_NS:
case TYPE_PTR:
case TYPE_TXT:
rrp->rdlength = strlen(data) + 1;
rrp->rdata.name = strxdup(data);
break;
case TYPE_A:
rrp->rdlength = 4;
rrp->rdata.addr = aton(data);
break;
case TYPE_HINFO:
rrp->rdlength = strlen(data) + 2;
rrp->rdata.hinfo.cpu = strxdup(data);
if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
rrp->rdlength += strlen(data);
rrp->rdata.hinfo.os = strxdup(data);
}
break;
case TYPE_MINFO:
rrp->rdlength = strlen(data) + 2;
rrp->rdata.minfo.rmailbx = strxdup(data);
if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
rrp->rdlength += strlen(data);
rrp->rdata.minfo.emailbx = strxdup(data);
}
break;
case TYPE_MX:
rrp->rdata.mx.pref = atoi(data);
rrp->rdlength = 2;
/* Get domain name of exchanger */
if((data = strtok(NULLCHAR,delim)) != NULLCHAR) {
rrp->rdlength += strlen(data) + 1;
rrp->rdata.mx.exch = strxdup(data);
}
break;
case TYPE_SOA:
rrp->rdata.soa = mxallocw(sizeof(struct soa));
/* Get domain name of master name server */
rrp->rdlength = strlen(data) + 1;
rrp->rdata.soa->mname = strxdup(data);
/* Get domain name of irresponsible person */
if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
rrp->rdata.soa->rname = strxdup(data);
rrp->rdlength += strlen(data) + 1;
}
data = strtok(NULLCHAR,delim);
if(*data == '(') { /* multiple line data */
/* Search file */
fgets(contline,LEN,fp);
if(feof(fp)) {
break;
}
data = strtok(contline,delim);
for(i = 0; i < 5; i++) {
if(*data == ';' || data == NULLCHAR) {
fgets(contline,LEN,fp);
if(feof(fp)) {
break;
}
data = strtok(contline,delim);
}
if(*data == ')') {
break;
}
if(isdigit(*data)) {
value = atol(data);
switch (i) {
case 0:
rrp->rdata.soa->serial = value;
break;
case 1:
rrp->rdata.soa->refresh = value;
break;
case 2:
rrp->rdata.soa->retry = value;
break;
case 3:
rrp->rdata.soa->expire = value;
break;
case 4:
rrp->rdata.soa->minimum = value;
break;
}
}
data = strtok(NULLCHAR,delim);
}
} else {
rrp->rdata.soa->serial = atol(data);
data = strtok(NULLCHAR,delim);
rrp->rdata.soa->refresh = atol(data);
data = strtok(NULLCHAR,delim);
rrp->rdata.soa->retry = atol(data);
data = strtok(NULLCHAR,delim);
rrp->rdata.soa->expire = atol(data);
data = strtok(NULLCHAR,delim);
rrp->rdata.soa->minimum = atol(data);
}
rrp->rdlength += 20;
break;
}
return rrp;
}
/* Print a resource record */
#ifndef ENH
static
#endif
void
put_rr(FILE *fp,struct rr *rrp,int addorg)
{
if(fp == NULLFILE || rrp == NULLRR) {
return;
}
fputs(rrp->name,fp);
if(addorg) {
if(rrp->name[strlen(rrp->name)-1] != '.' && rrp->origin != NULLCHAR) {
fprintf(fp,".%s",rrp->origin);
}
}
if(rrp->ttl){
fprintf(fp,"\t%lu",rrp->ttl);
}
if(rrp->class == CLASS_IN) {
fputs("\tIN",fp);
} else {
if(rrp->ttl == 0) {
fprintf(fp,"\t%lu",rrp->ttl);
}
fprintf(fp,"\t%u",rrp->class);
}
if(rrp->type < NDTYPES) {
fprintf(fp,"\t%s",type2str(rrp->type));
} else {
fprintf(fp,"\t%u",rrp->type);
}
if(rrp->rdlength != 0) {
fputc('\t',fp);
switch(rrp->type){
case TYPE_MINFO: /* Unsupported type */
fprintf(fp,"%s\t%s",rrp->rdata.minfo.rmailbx,rrp->rdata.minfo.emailbx);
break;
case TYPE_MD: /* Unsupported type */
case TYPE_MF: /* Unsupported type */
case TYPE_NULL: /* Unsupported type */
case TYPE_WKS: /* Unsupported type */
/*
fputs(rrp->rdata.data,fp);
break;
*/
case TYPE_CNAME:
case TYPE_MB:
case TYPE_MG:
case TYPE_MR:
case TYPE_NS:
case TYPE_PTR:
case TYPE_TXT:
/* These are all printable text strings */
fputs(rrp->rdata.data,fp);
break;
case TYPE_A:
fprintf(fp,"%s",inet_ntoa(rrp->rdata.addr));
break;
case TYPE_MX:
fprintf(fp,"%u\t%s",rrp->rdata.mx.pref,rrp->rdata.mx.exch);
break;
case TYPE_SOA:
fprintf(fp,"%s\t%s\t%lu\t%lu\t%lu\t%lu\t%lu",
rrp->rdata.soa->mname,
rrp->rdata.soa->rname,
rrp->rdata.soa->serial,
rrp->rdata.soa->refresh,
rrp->rdata.soa->retry,
rrp->rdata.soa->expire,
rrp->rdata.soa->minimum);
break;
case TYPE_HINFO:
fprintf(fp,"%s\t%s",rrp->rdata.hinfo.cpu,rrp->rdata.hinfo.os);
/*
break;
*/
default:
break;
}
}
fputc('\n',fp);
fflush(fp);
}
/* Free a domain message */
void
free_dhdr(struct dhdr *dp)
{
int i;
if(dp->qdcount) {
for(i = 0; i < dp->qdcount; i++) {
xfree(dp->qlist[i]->qname);
xfree(dp->qlist[i]);
}
xfree(dp->qlist);
}
if(dp->ancount) {
for(i = 0; i < dp->ancount; i++) {
free_rr(dp->ans[i]);
}
xfree(dp->ans);
}
if(dp->nscount) {
for(i = 0; i < dp->nscount; i++) {
free_rr(dp->ns[i]);
}
xfree(dp->ns);
}
if(dp->arcount) {
for(i = 0; i < dp->arcount; i++) {
free_rr(dp->add[i]);
}
xfree(dp->add);
}
xfree(dp);
}
int
ntohdomain(struct dhdr *dhdr,struct mbuf **bpp)
{
int i;
int16 tmp, len = len_p(*bpp);
char *cp, *msg = mxallocw(len);
memset(dhdr,0,sizeof(struct dhdr));
pullup(bpp,msg,len);
dhdr->id = get16(&msg[0]);
tmp = get16(&msg[2]);
if(tmp & DOM_RESPONSE) {
dhdr->qr = 1;
}
dhdr->opcode = (tmp >> 11) & 0xf;
if(tmp & DOM_AUTHORITY) {
dhdr->aa = 1;
}
if(tmp & DOM_TRUNC) {
dhdr->tc = 1;
}
if(tmp & DOM_DORECURSE) {
dhdr->rd = 1;
}
if(tmp & DOM_CANRECURSE) {
dhdr->ra = 1;
}
dhdr->rcode = tmp & 0xf;
dhdr->qdcount = get16(&msg[4]);
dhdr->ancount = get16(&msg[6]);
dhdr->nscount = get16(&msg[8]);
dhdr->arcount = get16(&msg[10]);
/* Now parse the variable length sections */
cp = &msg[12];
/* Question section */
if(dhdr->qdcount) {
dhdr->qlist = cxallocw(dhdr->qdcount,sizeof(struct quest *));
}
for(i = 0; i < dhdr->qdcount; i++) {
dhdr->qlist[i] = mxallocw(sizeof(struct quest));
if((cp = getq(dhdr->qlist[i],msg,cp)) == NULLCHAR) {
break;
}
}
/* Answer section */
if(dhdr->ancount) {
dhdr->ans = cxallocw(dhdr->ancount,sizeof(struct rr *));
}
for(i = 0; i < dhdr->ancount; i++) {
dhdr->ans[i] = mxallocw(sizeof(struct rr));
if((cp = ntohrr(dhdr->ans[i],msg,cp)) == NULLCHAR) {
break;
}
}
/* Name server (authority) section */
if(dhdr->nscount) {
dhdr->ns = cxallocw(dhdr->nscount,sizeof(struct rr *));
}
for(i = 0; i < dhdr->nscount; i++) {
dhdr->ns[i] = mxallocw(sizeof(struct rr));
if((cp = ntohrr(dhdr->ns[i],msg,cp)) == NULLCHAR) {
break;
}
}
/* Additional section */
if(dhdr->arcount) {
dhdr->add = cxallocw(dhdr->arcount,sizeof(struct rr *));
}
for(i = 0; i < dhdr->arcount; i++) {
dhdr->add[i] = mxallocw(sizeof(struct rr));
if((cp = ntohrr(dhdr->add[i],msg,cp)) == NULLCHAR) {
break;
}
}
xfree(msg);
return 0;
}
void
proc_answer(struct dhdr *dhdr,struct dserver *dp,FILE *dfp)
{
FILE *fp;
int i;
long ttl = 500; /* Default TTL for negative records without SOA */
struct rr *rrp;
/* Compute and update the round trip time if its a domain server */
if(dp != NULLDOM) {
int32 rtt = ((secclock() - (int32)dhdr->id)) * 1000;
int32 abserr = rtt > dp->srtt ? rtt - dp->srtt : dp->srtt - rtt;
dp->srtt = ((AGAIN-1) * dp->srtt + rtt + (AGAIN/2)) >> LAGAIN;
dp->mdev = ((DGAIN-1) * dp->mdev + abserr + (DGAIN/2)) >> LDGAIN;
dp->timeout = 4 * dp->mdev + dp->srtt;
}
if(DBloaded == 1 && dfp == NULLFILE) {
fp = NULLFILE; /* append to memory */
} else {
if(dfp == NULLFILE) {
if((fp = Fopen(Dfile,APPEND_TEXT,0,1)) == NULLFILE) {
return;
}
} else {
fp = dfp;
}
}
if(dhdr->aa && (dhdr->rcode == NAME_ERROR || dhdr->ancount == 0)) {
/* Add negative reply to file. This assumes that there was
* only one question, which is true for all questions we send.
*/
struct quest *qp = dhdr->qlist[0];
rrp = mxallocw(sizeof(struct rr));
rrp->name = strxdup(qp->qname);
rrp->type = qp->qtype;
rrp->class = qp->qclass;
rrp->ttl = ttl;
rrp->rdlength = 0; /* no data */
if(rrp->type == TYPE_A) {
if(add_rr(fp,rrp)) {
free_rr(rrp); /* was already there */
}
}
}
if(dhdr->rcode == NO_ERROR) {
for(i = 0; i < dhdr->ancount; i++) {
rrp = copy_rr(dhdr->ans[i]);
if(rrp->type == TYPE_SOA) {
ttl = rrp->ttl;
}
if(add_rr(fp,rrp)) {
free_rr(rrp);
}
}
for(i = 0; i < dhdr->nscount; i++) {
rrp = copy_rr(dhdr->ns[i]);
if(rrp->type == TYPE_SOA) {
ttl = rrp->ttl;
}
if(add_rr(fp,rrp)) {
free_rr(rrp);
}
}
for(i = 0; i < dhdr->arcount; i++) {
rrp = copy_rr(dhdr->add[i]);
if(rrp->type == TYPE_SOA) {
ttl = rrp->ttl;
}
if(add_rr(fp,rrp)) {
free_rr(rrp);
}
}
}
if(fp != NULLFILE && dfp == NULLFILE) {
Fclose(fp);
}
}
char *
type2str(int type)
{
static char *Dtypes[] = {
"Dt", "A", "NS", "MD", "MF", "CNAME", "SOA", "MB", "MG",
"MR", "NULL", "WKS", "PTR", "HINFO", "MINFO", "MX", "TXT"
};
if(type < NDTYPES) {
return Dtypes[type];
} else {
switch (type) {
case TYPE_AXFR:
return "AXFR";
case TYPE_MAILB:
return "MAILB";
case TYPE_MAILA:
return "MAILA";
case TYPE_ANY:
return "ANY";
}
}
return "UNKNOWN";
}
/* Return 1 if string appears to be an IP address in dotted decimal;
* return 0 otherwise (i.e., if string is a domain name)
*/
int
isaddr(char *s)
{
char c;
if(s != NULLCHAR) {
while((c = *s++) != '\0') {
if(c != '[' && !isdigit(c) && c != '.') {
return 0;
}
}
}
return 1;
}
struct dhdr *
bld_dhdr(int16 qr,int16 op,int16 flags,int16 rcode,char *name,int class,int type)
{
struct dhdr *dhdr = mxallocw(sizeof(struct dhdr));
if(flags & DOM_AUTHORITY) {
dhdr->aa = 1;
}
if(flags & DOM_TRUNC) {
dhdr->tc = 1;
}
if(flags & DOM_DORECURSE) {
dhdr->rd = 1;
}
if(flags & DOM_CANRECURSE) {
dhdr->ra = 1;
}
dhdr->qr = qr;
dhdr->opcode = op;
dhdr->rcode = rcode;
dhdr->id = (int16)secclock();
dhdr->qdcount = 1;
dhdr->qlist = cxallocw(dhdr->qdcount,sizeof(struct quest *));
dhdr->qlist[0] = mxallocw(sizeof(struct quest));
dhdr->qlist[0]->qname = strxdup(name);
dhdr->qlist[0]->qtype = type;
dhdr->qlist[0]->qclass = class;
return dhdr;
}
int
res_mkbuf(struct dhdr *dhdr,char *buffer,int16 buflen)
{
int16 parameter;
int i, count;
char *cp = buffer;
cp = put16(cp,dhdr->id);
parameter = (dhdr->qr) ? 0x8000 : 0;
parameter |= ((dhdr->opcode & 0x0f) << 11);
if(dhdr->aa) {
parameter |= DOM_AUTHORITY;
}
if(dhdr->tc) {
parameter |= DOM_TRUNC;
}
if(dhdr->rd) {
parameter |= DOM_DORECURSE;
}
if(dhdr->ra) {
parameter |= DOM_CANRECURSE;
}
parameter |= (dhdr->rcode & 0x0f);
cp = put16(cp,parameter);
cp = put16(cp,dhdr->qdcount);
cp = put16(cp,dhdr->ancount);
cp = put16(cp,dhdr->nscount);
cp = put16(cp,dhdr->arcount);
if((count = dhdr->qdcount) > 0) {
for(i = 0; i < count; i++) {
cp = dn_compress(cp,dhdr->qlist[i]->qname);
cp = put16(cp,dhdr->qlist[i]->qtype);
cp = put16(cp,dhdr->qlist[i]->qclass);
}
}
if((count = dhdr->ancount) > 0) {
for(i = 0; i < count; i++) {
cp = htonrr(dhdr->ans[i],cp);
}
}
if((count = dhdr->nscount) > 0) {
for(i = 0; i < count; i++) {
cp = htonrr(dhdr->ns[i],cp);
}
}
if((count = dhdr->arcount) > 0) {
for(i = 0; i < count; i++) {
cp = htonrr(dhdr->add[i],cp);
}
}
return (int)(cp - buffer);
}